/*

    DLStarRating
    Copyright (C) 2011 David Linsin <dlinsin@gmail.com> 

    All rights reserved. This program and the accompanying materials
    are made available under the terms of the Eclipse Public License v1.0
    which accompanies this distribution, and is available at
    http://www.eclipse.org/legal/epl-v10.html

 */

#import "DLStarRatingControl.h"
#import "DLStarView.h"
#import "UIView+Subviews.h"


@implementation DLStarRatingControl

#pragma mark -
#pragma mark Initialization

- (void)setupView {
	self.clipsToBounds = YES;
	currentIdx = -1;
    if(! _star){
	    _star = [[UIImage imageNamed:@"star.png"] retain];
    }
    if(!_highlightedStar){
        _highlightedStar = [[UIImage imageNamed:@"star_highlighted.png"] retain];
    }
    if(! _labelTextColor){
        _labelTextColor = [[UIColor sam_colorWithHex:@"747474"] retain];
    }

    for(UIView *subview in [self subviews]){
        [subview removeFromSuperview];
    }


    for (int i=0; i<numberOfStars; i++) {
        DLStarView *v = [[DLStarView alloc] initWithDefault:self.star highlighted:self.highlightedStar position:i allowFractions:self.isFractionalRatingEnabled];

        UILabel *lbTitle = [[UILabel alloc] initWithFrame:v.frame];
        lbTitle.tag = [self genLabelTag:i];
        lbTitle.textAlignment = NSTextAlignmentCenter;
        lbTitle.userInteractionEnabled = false;
        lbTitle.backgroundColor = [UIColor clearColor];
        lbTitle.textColor = self.labelTextColor;
        lbTitle.text = [NSString stringWithFormat:@"%d", i+1];

		[self addSubview:v];
        [self addSubview:lbTitle];
		[v release];
        [lbTitle release];
    }
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
		numberOfStars = kDefaultNumberOfStars;
        if (self.isFractionalRatingEnabled){
            numberOfStars *=kNumberOfFractions;
        }
		[self setupView];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame {
	self = [super initWithFrame:frame];
	if (self) {
		numberOfStars = kDefaultNumberOfStars;
        if (self.isFractionalRatingEnabled){
            numberOfStars *=kNumberOfFractions;
        }
        [self setupView];

	}
	return self;
}

- (id)initWithFrame:(CGRect)frame andStars:(NSUInteger)_numberOfStars isFractional:(BOOL)isFract{
	self = [super initWithFrame:frame];
	if (self) {
        self.isFractionalRatingEnabled = isFract;
		numberOfStars = _numberOfStars;
        if (self.isFractionalRatingEnabled){
            numberOfStars *=kNumberOfFractions;
        }
		[self setupView];
	}
	return self;
}

- (void)layoutSubviews {
	for (int i=0; i < numberOfStars; i++) {
        DLStarView *subStarView = (DLStarView*)[self subViewWithTag:i];
        subStarView.gap = _gap;
		[subStarView centerIn:self.frame with:numberOfStars];

        UILabel *subTitleView = (UILabel *) [self subViewWithTag:[self genLabelTag:i]];
        subTitleView.frame = subStarView.frame;
        subTitleView.hidden = ! self.isShowLabel;
	}
}

- (void)setLabelColor:(UIColor *)labelColor {
    if (_labelTextColor != labelColor) {
        [labelColor retain];
        [_labelTextColor release];
        _labelTextColor = labelColor;

        for (int i=0; i<numberOfStars; i++) {
            UILabel *label = (UILabel *) [self subViewWithTag:[self genLabelTag:i]];
            label.textColor = _labelTextColor;
        }
    }
}


- (void)setStar:(UIImage *)star {
    if (_star != star) {
        [star retain];
        [_star release];
        _star = star;

        [self setupView];
    }
}

- (void)setHighlightedStar:(UIImage *)highlightedStar {
    if (_highlightedStar != highlightedStar) {
        [highlightedStar retain];
        [_highlightedStar release];
        _highlightedStar = highlightedStar;

        [self setupView];
    }
}

- (void)setGap:(int)gap {
    _gap = gap;
    [self setNeedsLayout];
}

/*
- (void)setStar:(UIImage*)defaultStarImage highlightedStar:(UIImage*)highlightedStarImage atIndex:(int)index {
    DLStarView *selectedStar = (DLStarView*)[self subViewWithTag:index];
    
    // check if star exists
    if (!selectedStar) return;
    
    // check images for nil else use default stars
    defaultStarImage = (defaultStarImage) ? defaultStarImage : self.star;
    highlightedStarImage = (highlightedStarImage) ? highlightedStarImage : self.highlightedStar;
    
    [selectedStar setStarImage:defaultStarImage highlightedStarImage:highlightedStarImage];
}
*/

#pragma mark -
#pragma mark Touch Handling

- (UIButton*)starForPoint:(CGPoint)point {
	for (int i=0; i < numberOfStars; i++) {
		if (CGRectContainsPoint([self subViewWithTag:i].frame, point)) {
			return (UIButton*)[self subViewWithTag:i];
		}
	}
	return nil;
}

- (void)disableStarsDownToExclusive:(int)idx {
	for (int i=numberOfStars; i > idx; --i) {
		UIButton *b = (UIButton*)[self subViewWithTag:i];
		b.highlighted = NO;
	}
}

- (void)disableStarsDownTo:(int)idx {
	for (int i=numberOfStars; i >= idx; --i) {
		UIButton *b = (UIButton*)[self subViewWithTag:i];
		b.highlighted = NO;
	}
}


- (void)enableStarsUpTo:(int)idx {
	for (int i=0; i <= idx; i++) {
		UIButton *b = (UIButton*)[self subViewWithTag:i];
		b.highlighted = YES;
	}
}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"beginTrackingWithTouch");
	CGPoint point = [touch locationInView:self];	
	UIButton *pressedButton = [self starForPoint:point];
	if (pressedButton) {
		int idx = pressedButton.tag;
		if (pressedButton.highlighted) {
			[self disableStarsDownToExclusive:idx];
		} else {
			[self enableStarsUpTo:idx];
		}		
		currentIdx = idx;
	} 
	return YES;		
}

- (void)cancelTrackingWithEvent:(UIEvent *)event {
    NSLog(@"cancelTrackingWithEvent");
	[super cancelTrackingWithEvent:event];

    if(lastRating != self.rating){
        [self.delegate onRatingChange:self :self.rating];
        lastRating = self.rating;
    }

}

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"continueTrackingWithTouch");
    [self updateView:[touch locationInView:self]];
	return YES;
}

- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    NSLog(@"endTrackingWithTouch");
    [super endTrackingWithTouch:touch withEvent:event];

    [self updateView:[touch locationInView:self]];
}

- (void)updateView:(CGPoint) touchPoint {
    UIButton *pressedButton = [self starForPoint:touchPoint];
    if (pressedButton) {
        int idx = pressedButton.tag;
        UIButton *currentButton = (UIButton*)[self subViewWithTag:currentIdx];

        if (idx < currentIdx) {
            currentButton.highlighted = NO;
            currentIdx = idx;
            [self disableStarsDownToExclusive:idx];
        } else if (idx > currentIdx) {
            currentButton.highlighted = YES;
            pressedButton.highlighted = YES;
            currentIdx = idx;
            [self enableStarsUpTo:idx];
        }
    } else if (touchPoint.x < [self subViewWithTag:0].frame.origin.x) {
        ((UIButton*)[self subViewWithTag:0]).highlighted = NO;
        currentIdx = -1;
        [self disableStarsDownToExclusive:0];
    }

    if(lastRating != self.rating){
        [self.delegate onRatingChange:self :self.rating];
        lastRating = self.rating;
    }
}

- (UILabel *)labelIn:(int)position {
    if(position >=0 && position < numberOfStars){
        return (UILabel *) [self subViewWithTag:[self genLabelTag:position]];
    }
    return nil;
}

- (int) genLabelTag:(int)position {
    return position + numberOfStars;
}

- (float)maxRating {
    return numberOfStars;
}


#pragma mark -
#pragma mark Rating Property

- (void)setRating:(float)_rating {
    if (self.isFractionalRatingEnabled) {
        _rating *=kNumberOfFractions;
    }
	[self disableStarsDownTo:0];
	currentIdx = (int)_rating-1;
	[self enableStarsUpTo:currentIdx];
}

- (float)rating {
    if (self.isFractionalRatingEnabled) {
        return (float)(currentIdx+1)/kNumberOfFractions;
    }
	return (NSUInteger)currentIdx+1;
}


#pragma mark -
#pragma mark Memory Management

- (void)dealloc {
	self.star = nil;
	self.highlightedStar = nil;
    self.labelColor = nil;
	self.delegate = nil;
	[super dealloc];
}

@end
